package com.hxh.rpc.consumer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;

/**
 * 扫描@RpcConsumer注解属性，实现远程调用
 *
 * @author hxh
 * @date 2022/3/4
 * @since 1.0
 */
@Slf4j
public class RpcConsumerPostProcessor implements BeanFactoryPostProcessor, BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            String beanClassName = beanDefinition.getBeanClassName();
            if (!StringUtils.hasText(beanClassName)) {
                continue;
            }
            Class<?> clazz = ClassUtils.resolveClassName(beanClassName, this.classLoader);
            ReflectionUtils.doWithFields(clazz, this::processConsumerBeanDefinition);
        }
    }

    private void processConsumerBeanDefinition(Field field) {
        RpcConsumer rpcConsumer = AnnotationUtils.findAnnotation(field, RpcConsumer.class);
        if (rpcConsumer == null) {
            return;
        }
        log.info("find a rpcConsumer field: {}", field);
        BeanDefinitionBuilder.genericBeanDefinition(RpcConsumerFactoryBean.class)
                .setInitMethodName("init")
                .addPropertyValue("interfaceClass", field.getType())
                .addPropertyValue("serviceVersion", rpcConsumer.serviceVersion());
    }

    @Override
    public void setBeanClassLoader(@NonNull ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
}
